Convert CargoResult, CargoError into an implementation provided by error-chain. The previous is_human machinery is mostly removed; now errors are displayed unless of the Internal kind, verbose mode will print all errors.
"curl 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"docopt 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
"fs2 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "backtrace"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "backtrace-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "backtrace-sys"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "bitflags"
version = "0.7.0"
version = "0.9.0"
dependencies = [
"curl 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "dbghelp-sys"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "docopt"
version = "0.7.0"
"regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "error-chain"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "backtrace 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "filetime"
version = "0.1.10"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "rustc-demangle"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "rustc-serialize"
version = "0.3.24"
"checksum advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e06588080cb19d0acb6739808aafa5f26bfb2ca015b2b6370028b44cf7cb8a9a"
"checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66"
"checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699"
+"checksum backtrace 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "72f9b4182546f4b04ebc4ab7f84948953a118bd6021a1b6a6c909e3e94f6be76"
+"checksum backtrace-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d192fd129132fbc97497c1f2ec2c2c5174e376b95f535199ef4fe0a293d33842"
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
"checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4"
"checksum bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f382711e76b9de6c744cc00d0497baba02fb00a787f088c879f01d09468e32"
"checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97"
"checksum curl 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c90e1240ef340dd4027ade439e5c7c2064dd9dc652682117bd50d1486a3add7b"
"checksum curl-sys 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "23e7e544dc5e1ba42c4a4a678bd47985e84b9c3f4d3404c29700622a029db9c3"
+"checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850"
"checksum docopt 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab32ea6e284d87987066f21a9e809a73c14720571ef34516f0890b3d355ccfd8"
"checksum dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80c8b71fd71146990a9742fc06dcbbde19161a267e0ad4e572c35162f4578c90"
"checksum env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e3856f1697098606fc6cb97a93de88ca3f3bc35bb878c725920e6e82ecf05e83"
+"checksum error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9435d864e017c3c6afeac1654189b06cdb491cf2ff73dbf0d73b0f292f42ff8"
"checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922"
"checksum flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)" = "36df0166e856739905cd3d7e0b210fe818592211a008862599845e012d8d304c"
"checksum foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e4056b9bd47f8ac5ba12be771f77a0dae796d1bbaaf5fd0b9c2d38b69b8a29d"
"checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01"
"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957"
"checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457"
+"checksum rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3058a43ada2c2d0b92b3ae38007a2d0fa5e9db971be260e0171408a4ff471c95"
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
"checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
curl = "0.4.6"
docopt = "0.7"
env_logger = "0.4"
+error-chain = "0.10.0"
filetime = "0.1"
flate2 = "0.2"
fs2 = "0.4"
use cargo::core::Workspace;
use cargo::ops::{self, MessageFormat, Packages};
-use cargo::util::{CliResult, CliError, Human, Config, human};
+use cargo::util::{CliResult, CliError, Config, human, CargoErrorKind};
use cargo::util::important_paths::{find_root_manifest_for_wd};
#[derive(RustcDecodable)]
Some(err) => {
Err(match err.exit.as_ref().and_then(|e| e.code()) {
Some(i) => CliError::new(human("bench failed"), i),
- None => CliError::new(Box::new(Human(err)), 101)
+ None => CliError::new(CargoErrorKind::CargoTestErrorKind(err).into(), 101)
})
}
}
use std::path::{Path, PathBuf};
use cargo::core::shell::{Verbosity, ColorConfig};
-use cargo::util::{self, CliResult, lev_distance, Config, human, CargoResult};
+use cargo::util::{self, CliResult, lev_distance, Config, human, CargoResult, CargoError, CargoErrorKind};
use cargo::util::CliError;
#[derive(RustcDecodable)]
Err(e) => e,
};
- if let Some(code) = err.exit.as_ref().and_then(|c| c.code()) {
- Err(CliError::code(code))
- } else {
- Err(CliError::new(Box::new(err), 101))
+ if let CargoError(CargoErrorKind::ProcessErrorKind(ref perr), ..) = err {
+ if let Some(code) = perr.exit.as_ref().and_then(|c| c.code()) {
+ return Err(CliError::code(code));
+ }
}
+ Err(CliError::new(err, 101))
}
/// List all runnable commands
use cargo;
-use cargo::util::{CliResult, CliError, human, ChainError, Config};
+use cargo::util::{CliResult, CliError, human, Config};
use cargo::util::important_paths::{find_root_manifest_for_wd};
#[derive(RustcDecodable)]
let root = find_root_manifest_for_wd(flags.flag_manifest_path, config.cwd())?;
let string = root.to_str()
- .chain_error(|| human("Your project path contains \
+ .ok_or_else(|| human("Your project path contains \
characters not representable in \
Unicode"))
.map_err(|e| CliError::new(e, 1))?;
use cargo::ops;
use cargo::core::{SourceId, Source};
use cargo::sources::RegistrySource;
-use cargo::util::{CliResult, Config, human, ChainError};
+use cargo::util::{CliResult, CargoResultExt, Config, human};
#[derive(RustcDecodable)]
pub struct Options {
println!("please visit {}me and paste the API Token below", host);
let mut line = String::new();
let input = io::stdin();
- input.lock().read_line(&mut line).chain_error(|| {
+ input.lock().read_line(&mut line).chain_err(|| {
human("failed to read stdin")
})?;
line
use cargo::core::Workspace;
use cargo::ops::{self, MessageFormat, Packages};
-use cargo::util::{CliResult, CliError, Config, Human};
+use cargo::util::{CliResult, CliError, Config, CargoErrorKind};
use cargo::util::important_paths::{find_root_manifest_for_wd};
#[derive(RustcDecodable)]
// bad and we always want to forward that up.
let exit = match err.exit.clone() {
Some(exit) => exit,
- None => return Err(CliError::new(Box::new(Human(err)), 101)),
+ None => return Err(CliError::new(CargoErrorKind::ProcessErrorKind(err).into(), 101)),
};
// If `-q` was passed then we suppress extra error information about
Err(if options.flag_quiet == Some(true) {
CliError::code(exit_code)
} else {
- CliError::new(Box::new(Human(err)), exit_code)
+ CliError::new(CargoErrorKind::ProcessErrorKind(err).into(), exit_code)
})
}
}
use cargo::core::Workspace;
use cargo::ops::{self, MessageFormat, Packages};
-use cargo::util::{CliResult, CliError, Human, human, Config};
+use cargo::util::{CliResult, CliError, human, Config, CargoErrorKind};
use cargo::util::important_paths::find_root_manifest_for_wd;
#[derive(RustcDecodable)]
Some(err) => {
Err(match err.exit.as_ref().and_then(|e| e.code()) {
Some(i) => CliError::new(human(err.hint()), i),
- None => CliError::new(Box::new(Human(err)), 101),
+ None => CliError::new(CargoErrorKind::CargoTestErrorKind(err).into(), 101),
})
}
}
use serde::ser;
use core::{SourceId, Summary, PackageId};
-use util::{CargoError, CargoResult, Cfg, CfgExpr, ChainError, human, Config};
+use util::{Cfg, CfgExpr, human, Config};
+use util::errors::{CargoResult, CargoResultExt, CargoError};
/// Information about a dependency requested by a Cargo manifest.
/// Cheap to copy.
Ok(requirement)
}
- e => Err(From::from(e)),
+ e => Err(e.into()),
}
},
Ok(v) => Ok(v),
}
impl FromStr for Platform {
- type Err = Box<CargoError>;
+ type Err = CargoError;
fn from_str(s: &str) -> CargoResult<Platform> {
if s.starts_with("cfg(") && s.ends_with(")") {
let s = &s[4..s.len()-1];
- s.parse().map(Platform::Cfg).chain_error(|| {
+ s.parse().map(Platform::Cfg).chain_err(|| {
human(format!("failed to parse `{}` as a cfg expression", s))
})
} else {
use core::{Dependency, Manifest, PackageId, SourceId, Target};
use core::{Summary, SourceMap};
use ops;
-use util::{CargoResult, Config, LazyCell, ChainError, internal, human, lev_distance};
+use util::{Config, LazyCell, internal, human, lev_distance};
+use util::errors::{CargoResult, CargoResultExt};
/// Information about a package that is available somewhere in the file system.
///
}
pub fn get(&self, id: &PackageId) -> CargoResult<&Package> {
- let slot = self.packages.iter().find(|p| p.0 == *id).chain_error(|| {
+ let slot = self.packages.iter().find(|p| p.0 == *id).ok_or_else(|| {
internal(format!("couldn't find `{}` in package set", id))
})?;
let slot = &slot.1;
return Ok(pkg)
}
let mut sources = self.sources.borrow_mut();
- let source = sources.get_mut(id.source_id()).chain_error(|| {
+ let source = sources.get_mut(id.source_id()).ok_or_else(|| {
internal(format!("couldn't find source for `{}`", id))
})?;
- let pkg = source.download(id).chain_error(|| {
+ let pkg = source.download(id).chain_err(|| {
human("unable to get packages from source")
})?;
assert!(slot.fill(pkg).is_ok());
use std::cmp::Ordering;
-use std::error::Error;
use std::fmt::{self, Formatter};
use std::hash::Hash;
use std::hash;
use serde::de;
use serde::ser;
-use util::{CargoResult, CargoError, ToSemver};
+use util::{CargoResult, ToSemver};
use core::source::SourceId;
/// Identifier for a specific version of a package in a specific source.
}
}
-#[derive(Clone, Debug, PartialEq)]
-pub enum PackageIdError {
- InvalidVersion(String),
- InvalidNamespace(String)
-}
-
-impl Error for PackageIdError {
- fn description(&self) -> &str { "failed to parse package id" }
-}
-
-impl fmt::Display for PackageIdError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- PackageIdError::InvalidVersion(ref v) => {
- write!(f, "invalid version: {}", *v)
- }
- PackageIdError::InvalidNamespace(ref ns) => {
- write!(f, "invalid namespace: {}", *ns)
- }
- }
- }
-}
-
-impl CargoError for PackageIdError {
- fn is_human(&self) -> bool { true }
-}
-
-impl From<PackageIdError> for Box<CargoError> {
- fn from(t: PackageIdError) -> Box<CargoError> { Box::new(t) }
-}
-
impl PackageId {
pub fn new<T: ToSemver>(name: &str, version: T,
sid: &SourceId) -> CargoResult<PackageId> {
- let v = version.to_semver().map_err(PackageIdError::InvalidVersion)?;
+ let v = version.to_semver()?;
Ok(PackageId {
inner: Arc::new(PackageIdInner {
name: name.to_string(),
use url::Url;
use core::PackageId;
-use util::{CargoResult, ToUrl, human, ToSemver, ChainError};
+use util::{ToUrl, human, ToSemver};
+use util::errors::{CargoResult, CargoResultExt};
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct PackageIdSpec {
pub fn query_str<'a, I>(spec: &str, i: I) -> CargoResult<&'a PackageId>
where I: IntoIterator<Item=&'a PackageId>
{
- let spec = PackageIdSpec::parse(spec).chain_error(|| {
+ let spec = PackageIdSpec::parse(spec).chain_err(|| {
human(format!("invalid package id specification: `{}`", spec))
})?;
spec.query(i)
let frag = url.fragment().map(|s| s.to_owned());
url.set_fragment(None);
let (name, version) = {
- let mut path = url.path_segments().chain_error(|| {
+ let mut path = url.path_segments().ok_or_else(|| {
human(format!("pkgid urls must have a path: {}", url))
})?;
- let path_name = path.next_back().chain_error(|| {
+ let path_name = path.next_back().ok_or_else(|| {
human(format!("pkgid urls must have at least one path \
component: {}", url))
})?;
use core::{Source, SourceId, SourceMap, Summary, Dependency, PackageId, Package};
use core::PackageSet;
-use util::{CargoResult, ChainError, Config, human, profile};
+use util::{Config, human, profile};
+use util::errors::{CargoResult, CargoResultExt};
use sources::config::SourceConfigMap;
/// Source of information about a group of packages.
// Ensure the source has fetched all necessary remote data.
let _p = profile::start(format!("updating: {}", source_id));
self.sources.get_mut(source_id).unwrap().update()
- }).chain_error(|| human(format!("Unable to update {}", source_id)))
+ })().chain_err(|| human(format!("Unable to update {}", source_id)))
}
fn query_overrides(&mut self, dep: &Dependency)
impl<'cfg> Registry for PackageRegistry<'cfg> {
fn query(&mut self, dep: &Dependency) -> CargoResult<Vec<Summary>> {
// Ensure the requested source_id is loaded
- self.ensure_loaded(dep.source_id(), Kind::Normal).chain_error(|| {
+ self.ensure_loaded(dep.source_id(), Kind::Normal).chain_err(|| {
human(format!("failed to load source for a dependency \
on `{}`", dep.name()))
})?;
use serde::de;
use core::{Package, PackageId, SourceId, Workspace};
-use util::{CargoResult, Graph, Config, internal, ChainError, CargoError};
+use util::{Graph, Config, internal};
+use util::errors::{CargoResult, CargoResultExt, CargoError};
use super::Resolve;
for (k, v) in metadata.iter().filter(|p| p.0.starts_with(prefix)) {
to_remove.push(k.to_string());
let k = &k[prefix.len()..];
- let enc_id: EncodablePackageId = k.parse().chain_error(|| {
+ let enc_id: EncodablePackageId = k.parse().chain_err(|| {
internal("invalid encoding of checksum in lockfile")
})?;
let id = match lookup_id(&enc_id) {
}
impl FromStr for EncodablePackageId {
- type Err = Box<CargoError>;
+ type Err = CargoError;
fn from_str(s: &str) -> CargoResult<EncodablePackageId> {
let mut s = s.splitn(3, ' ');
let name = s.next().unwrap();
- let version = s.next().chain_error(|| {
+ let version = s.next().ok_or_else(|| {
internal("invalid serialized PackageId")
})?;
let source_id = match s.next() {
use core::{PackageId, Registry, SourceId, Summary, Dependency};
use core::PackageIdSpec;
-use util::{CargoResult, Graph, human, CargoError};
+use util::{Graph, human};
+use util::errors::{CargoResult, CargoError};
use util::profile;
-use util::ChainError;
use util::graph::{Nodes, Edges};
pub use self::encode::{EncodableResolve, EncodableDependency, EncodablePackageId};
parent: &Summary,
dep: &Dependency,
prev_active: &[Rc<Summary>],
- candidates: &[Candidate]) -> Box<CargoError> {
+ candidates: &[Candidate]) -> CargoError {
if candidates.len() > 0 {
let mut msg = format!("failed to select a version for `{}` \
(required by `{}`):\n\
debug!("found an override for {} {}", dep.name(), dep.version_req());
let mut summaries = registry.query(dep)?.into_iter();
- let s = summaries.next().chain_error(|| {
+ let s = summaries.next().ok_or_else(|| {
human(format!("no matching package for override `{}` found\n\
location searched: {}\n\
version required: {}",
use core::{Package, VirtualManifest, EitherManifest, SourceId};
use core::{PackageIdSpec, Dependency, Profile, Profiles};
use ops;
-use util::{Config, CargoResult, Filesystem, human, ChainError};
+use util::{Config, Filesystem, human};
+use util::errors::{CargoResult, CargoResultExt};
use util::paths;
/// The core abstraction in Cargo for working with a workspace of crates.
Some(p) => p,
None => return Ok(Vec::new()),
};
- let res = glob(path).chain_error(|| {
+ let res = glob(path).chain_err(|| {
human(format!("could not parse pattern `{}`", &path))
})?;
res.map(|p| {
- p.chain_error(|| {
+ p.chain_err(|| {
human(format!("unable to match path to pattern `{}`", &path))
})
}).collect()
#![deny(unused)]
#![cfg_attr(test, deny(warnings))]
+#![recursion_limit="128"]
#[cfg(test)] extern crate hamcrest;
+#[macro_use] extern crate error_chain;
#[macro_use] extern crate log;
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate serde_json;
use std::io;
use std::fmt;
+use std::error::Error;
+use error_chain::ChainedError;
use rustc_serialize::Decodable;
use serde::ser;
use docopt::Docopt;
use core::shell::Verbosity::{Verbose};
use term::color::{BLACK};
-pub use util::{CargoError, CargoResult, CliError, CliResult, human, Config, ChainError};
+pub use util::{CargoError, CargoErrorKind, CargoResult, CliError, CliResult, human, Config};
pub const CARGO_ENV: &'static str = "CARGO";
shell.say(&error, BLACK)
};
- if !handle_cause(&error, shell) || hide {
+ if !handle_cause(error, shell) || hide {
let _ = shell.err().say("\nTo learn more, run the command again \
with --verbose.".to_string(), BLACK);
}
std::process::exit(exit_code)
}
-pub fn handle_error(err: &CargoError, shell: &mut MultiShell) {
- debug!("handle_error; err={:?}", err);
+pub fn handle_error(err: CargoError, shell: &mut MultiShell) {
+ debug!("handle_error; err={:?}", &err);
- let _ignored_result = shell.error(err);
+ let _ignored_result = shell.error(&err);
handle_cause(err, shell);
}
-fn handle_cause(mut cargo_err: &CargoError, shell: &mut MultiShell) -> bool {
- let verbose = shell.get_verbose();
- let mut err;
- loop {
- cargo_err = match cargo_err.cargo_cause() {
- Some(cause) => cause,
- None => { err = cargo_err.cause(); break }
- };
- if verbose != Verbose && !cargo_err.is_human() { return false }
- print(cargo_err.to_string(), shell);
- }
- loop {
- let cause = match err { Some(err) => err, None => return true };
- if verbose != Verbose { return false }
- print(cause.to_string(), shell);
- err = cause.cause();
- }
-
+fn handle_cause<E, EKind>(cargo_err: E, shell: &mut MultiShell) -> bool where E: ChainedError<ErrorKind=EKind> + 'static {
fn print(error: String, shell: &mut MultiShell) {
let _ = shell.err().say("\nCaused by:", BLACK);
let _ = shell.err().say(format!(" {}", error), BLACK);
}
+
+ unsafe fn extend_lifetime(r: &Error) -> &'static Error {
+ std::mem::transmute::<&Error, &'static Error>(r)
+ }
+
+ let verbose = shell.get_verbose();
+
+ if verbose == Verbose {
+ //The first error has already been printed to the shell
+ //Print all remaining errors
+ for err in cargo_err.iter().skip(1) {
+ print(err.to_string(), shell);
+ }
+ }
+ else {
+ //The first error has already been printed to the shell
+ //Print remaining errors until one marked as Internal appears
+ for err in cargo_err.iter().skip(1) {
+ let err = unsafe { extend_lifetime(err) };
+ if let Some(&CargoError(CargoErrorKind::Internal(..), ..)) = err.downcast_ref::<CargoError>() {
+ return false;
+ }
+
+ print(err.to_string(), shell);
+ }
+ }
+
+ true
}
+
pub fn version() -> VersionInfo {
macro_rules! env_str {
($name:expr) => { env!($name).to_string() }
use std::path::Path;
use core::{Profiles, Workspace};
-use util::{CargoResult, human, ChainError, Config};
+use util::{human, Config};
+use util::errors::{CargoResult, CargoResultExt};
use ops::{self, Context, BuildConfig, Kind, Unit};
pub struct CleanOptions<'a> {
fn rm_rf(path: &Path) -> CargoResult<()> {
let m = fs::metadata(path);
if m.as_ref().map(|s| s.is_dir()).unwrap_or(false) {
- fs::remove_dir_all(path).chain_error(|| {
+ fs::remove_dir_all(path).chain_err(|| {
human("could not remove build directory")
})?;
} else if m.is_ok() {
- fs::remove_file(path).chain_error(|| {
+ fs::remove_file(path).chain_err(|| {
human("failed to remove build artifact")
})?;
}
use core::{PackageId, Workspace};
use ops::{self, CompileFilter, DefaultExecutor};
use sources::{GitSource, PathSource, SourceConfigMap};
-use util::{CargoResult, ChainError, Config, human, internal};
+use util::{Config, human, internal};
use util::{Filesystem, FileLock};
+use util::errors::{CargoResult, CargoResultExt};
#[derive(Deserialize, Serialize)]
#[serde(untagged)]
let path = source_id.url().to_file_path().ok()
.expect("path sources must have a valid path");
let mut src = PathSource::new(&path, source_id, config);
- src.update().chain_error(|| {
+ src.update().chain_err(|| {
human(format!("`{}` is not a crate root; specify a crate to \
install from crates.io, or use --path or --git to \
specify an alternate source", path.display()))
let compile = ops::compile_ws(&ws,
Some(source),
opts,
- Arc::new(DefaultExecutor)).chain_error(|| {
+ Arc::new(DefaultExecutor)).chain_err(|| {
if let Some(td) = td_opt.take() {
// preserve the temporary directory, so the user can inspect it
td.into_path();
continue
}
}
- fs::copy(src, &dst).chain_error(|| {
+ fs::copy(src, &dst).chain_err(|| {
human(format!("failed to copy `{}` to `{}`", src.display(),
dst.display()))
})?;
let src = staging_dir.path().join(bin);
let dst = dst.join(bin);
config.shell().status("Installing", dst.display())?;
- fs::rename(&src, &dst).chain_error(|| {
+ fs::rename(&src, &dst).chain_err(|| {
human(format!("failed to move `{}` to `{}`", src.display(),
dst.display()))
})?;
let src = staging_dir.path().join(bin);
let dst = dst.join(bin);
config.shell().status("Replacing", dst.display())?;
- fs::rename(&src, &dst).chain_error(|| {
+ fs::rename(&src, &dst).chain_err(|| {
human(format!("failed to move `{}` to `{}`", src.display(),
dst.display()))
})?;
match write_result {
// Replacement error (if any) isn't actually caused by write error
// but this seems to be the only way to show both.
- Err(err) => result.chain_error(|| err)?,
+ Err(err) => result.chain_err(|| err)?,
Ok(_) => result?,
}
(|| -> CargoResult<_> {
let mut contents = String::new();
file.read_to_string(&mut contents)?;
- let listing = toml::from_str(&contents).chain_error(|| {
+ let listing = toml::from_str(&contents).chain_err(|| {
internal("invalid TOML found for metadata")
})?;
match listing {
Ok(CrateListingV1 { v1: BTreeMap::new() })
}
}
- }).chain_error(|| {
+ })().chain_err(|| {
human("failed to parse crate metadata")
})
}
let data = toml::to_string(&CrateListing::V1(listing))?;
file.write_all(data.as_bytes())?;
Ok(())
- }).chain_error(|| {
+ })().chain_err(|| {
human("failed to write crate metadata")
})
}
use core::Workspace;
use ops::is_bad_artifact_name;
-use util::{GitRepo, HgRepo, PijulRepo, CargoResult, human, ChainError, internal};
+use util::{GitRepo, HgRepo, PijulRepo, human, internal};
use util::{Config, paths};
+use util::errors::{CargoResult, CargoResultExt};
use toml;
path.as_os_str());
}
- let dir_name = path.file_name().and_then(|s| s.to_str()).chain_error(|| {
+ let dir_name = path.file_name().and_then(|s| s.to_str()).ok_or_else(|| {
human(&format!("cannot create a project with a non-unicode name: {:?}",
path.file_name().unwrap()))
})?;
bin: opts.bin,
};
- mk(config, &mkopts).chain_error(|| {
+ mk(config, &mkopts).chain_err(|| {
human(format!("Failed to create project `{}` at `{}`",
name, path.display()))
})
source_files: src_paths_types,
};
- mk(config, &mkopts).chain_error(|| {
+ mk(config, &mkopts).chain_err(|| {
human(format!("Failed to create project `{}` at `{}`",
name, path.display()))
})
use core::{Package, Workspace, Source, SourceId};
use sources::PathSource;
-use util::{self, CargoResult, human, internal, ChainError, Config, FileLock};
+use util::{self, human, internal, Config, FileLock};
+use util::errors::{CargoResult, CargoResultExt};
use ops::{self, DefaultExecutor};
pub struct PackageOpts<'cfg> {
// it exists.
config.shell().status("Packaging", pkg.package_id().to_string())?;
dst.file().set_len(0)?;
- tar(ws, &src, dst.file(), &filename).chain_error(|| {
+ tar(ws, &src, dst.file(), &filename).chain_err(|| {
human("failed to prepare local package for uploading")
})?;
if opts.verify {
dst.seek(SeekFrom::Start(0))?;
- run_verify(ws, dst.file(), opts).chain_error(|| {
+ run_verify(ws, dst.file(), opts).chain_err(|| {
human("failed to verify package tarball")
})?
}
{
let src_path = dst.path();
let dst_path = dst.parent().join(&filename);
- fs::rename(&src_path, &dst_path).chain_error(|| {
+ fs::rename(&src_path, &dst_path).chain_err(|| {
human("failed to move temporary tarball into final location")
})?;
}
for file in src.list_files(pkg)?.iter() {
let relative = util::without_prefix(&file, &root).unwrap();
check_filename(relative)?;
- let relative = relative.to_str().chain_error(|| {
+ let relative = relative.to_str().ok_or_else(|| {
human(format!("non-utf8 path in source directory: {}",
relative.display()))
})?;
// unpack the selectors 0.4.0 crate on crates.io. Either that or take a
// look at rust-lang/cargo#2326
let mut header = Header::new_ustar();
- header.set_path(&path).chain_error(|| {
+ header.set_path(&path).chain_err(|| {
human(format!("failed to add to archive: `{}`", relative))
})?;
- let mut file = File::open(file).chain_error(|| {
+ let mut file = File::open(file).chain_err(|| {
human(format!("failed to open for archiving: `{}`", file.display()))
})?;
- let metadata = file.metadata().chain_error(|| {
+ let metadata = file.metadata().chain_err(|| {
human(format!("could not learn metadata for: `{}`", relative))
})?;
header.set_metadata(&metadata);
let orig = Path::new(&path).with_file_name("Cargo.toml.orig");
header.set_path(&orig)?;
header.set_cksum();
- ar.append(&header, &mut file).chain_error(|| {
+ ar.append(&header, &mut file).chain_err(|| {
internal(format!("could not archive source file `{}`", relative))
})?;
header.set_mode(0o644);
header.set_size(toml.len() as u64);
header.set_cksum();
- ar.append(&header, toml.as_bytes()).chain_error(|| {
+ ar.append(&header, toml.as_bytes()).chain_err(|| {
internal(format!("could not archive source file `{}`", relative))
})?;
} else {
header.set_cksum();
- ar.append(&header, &mut file).chain_error(|| {
+ ar.append(&header, &mut file).chain_err(|| {
internal(format!("could not archive source file `{}`", relative))
})?;
}
use std::path::{Path, PathBuf};
use core::{Package, SourceId, PackageId, EitherManifest};
-use util::{self, paths, CargoResult, human, Config, ChainError};
+use util::{self, paths, human, Config};
+use util::errors::{CargoResult, CargoResultExt};
use util::important_paths::find_project_manifest_exact;
use util::toml::Layout;
let layout = Layout::from_project_path(path.parent().unwrap());
let root = layout.root.clone();
- util::toml::to_manifest(&contents, source_id, layout, config).chain_error(|| {
+ util::toml::to_manifest(&contents, source_id, layout, config).chain_err(|| {
human(format!("failed to parse manifest at `{}`",
root.join("Cargo.toml").display()))
})
return Ok(())
}
Err(e) => {
- return Err(human(e)).chain_error(|| {
+ return Err(human(e)).chain_err(|| {
human(format!("failed to read directory `{}`", path.display()))
})
}
use std::path::Path;
use ops::{self, Packages};
-use util::{self, human, CargoResult, ProcessError};
+use util::{self, human, CargoResult, CargoError, ProcessError};
+use util::errors::CargoErrorKind;
use core::Workspace;
pub fn run(ws: &Workspace,
process.args(args).cwd(config.cwd());
config.shell().status("Running", process.to_string())?;
- Ok(process.exec_replace().err())
+
+ let result = process.exec_replace();
+
+ match result {
+ Ok(()) => Ok(None),
+ Err(CargoError(CargoErrorKind::ProcessErrorKind(e), ..)) => Ok(Some(e)),
+ Err(e) => Err(e)
+ }
}
use core::{Package, PackageId, PackageSet, Resolve, Target, Profile};
use core::{TargetKind, Profiles, Dependency, Workspace};
use core::dependency::Kind as DepKind;
-use util::{self, CargoResult, ChainError, internal, Config, profile, Cfg, CfgExpr, human};
+use util::{self, internal, Config, profile, Cfg, CfgExpr, human};
+use util::errors::{CargoResult, CargoResultExt};
use super::TargetConfig;
use super::custom_build::{BuildState, BuildScripts};
pub fn prepare(&mut self) -> CargoResult<()> {
let _p = profile::start("preparing layout");
- self.host.prepare().chain_error(|| {
+ self.host.prepare().chain_err(|| {
internal(format!("couldn't prepare build directories"))
})?;
match self.target {
Some(ref mut target) => {
- target.prepare().chain_error(|| {
+ target.prepare().chain_err(|| {
internal(format!("couldn't prepare build directories"))
})?;
}
let output = with_cfg.exec_with_output().or_else(|_| {
has_cfg_and_sysroot = false;
process.exec_with_output()
- }).chain_error(|| {
+ }).chain_err(|| {
human(format!("failed to run `rustc` to learn about \
target-specific information"))
})?;
use std::sync::{Mutex, Arc};
use core::PackageId;
-use util::{CargoResult, Human, Freshness, Cfg};
-use util::{internal, ChainError, profile, paths};
+use util::{Freshness, Cfg};
+use util::errors::{CargoResult, CargoResultExt, CargoError};
+use util::{internal, profile, paths};
use util::machine_message;
use super::job::Work;
// If we have an old build directory, then just move it into place,
// otherwise create it!
if fs::metadata(&build_output).is_err() {
- fs::create_dir(&build_output).chain_error(|| {
+ fs::create_dir(&build_output).chain_err(|| {
internal("failed to create script output directory for \
build command")
})?;
let build_state = build_state.outputs.lock().unwrap();
for (name, id) in lib_deps {
let key = (id.clone(), kind);
- let state = build_state.get(&key).chain_error(|| {
+ let state = build_state.get(&key).ok_or_else(|| {
internal(format!("failed to locate build state for env \
vars: {}/{:?}", id, kind))
})?;
let output = cmd.exec_with_streaming(
&mut |out_line| { state.stdout(out_line); Ok(()) },
&mut |err_line| { state.stderr(err_line); Ok(()) },
- ).map_err(|mut e| {
- e.desc = format!("failed to run custom build command for `{}`\n{}",
- pkg_name, e.desc);
- Human(e)
+ ).map_err(|e| {
+ let desc = e.description().to_string();
+ CargoError::with_chain(e, format!("failed to run custom build command for `{}`\n{}",
+ pkg_name, desc))
})?;
+
paths::write(&output_file, &output.stdout)?;
// After the build command has finished running, we need to be sure to
use core::{Package, TargetKind};
use util;
-use util::{CargoResult, Fresh, Dirty, Freshness, internal, profile, ChainError};
+use util::{Fresh, Dirty, Freshness, internal, profile};
+use util::errors::{CargoResult, CargoResultExt};
use util::paths;
use super::job::Work;
if compare.is_err() {
let source_id = unit.pkg.package_id().source_id();
let sources = cx.packages.sources();
- let source = sources.get(source_id).chain_error(|| {
+ let source = sources.get(source_id).ok_or_else(|| {
internal("missing package source")
})?;
source.verify(unit.pkg.package_id())?;
fn update_local(&self) -> CargoResult<()> {
match self.local {
LocalFingerprint::MtimeBased(ref slot, ref path) => {
- let meta = fs::metadata(path).chain_error(|| {
- internal(format!("failed to stat `{}`", path.display()))
- })?;
+ let meta = fs::metadata(path)
+ .chain_err(|| {
+ internal(format!("failed to stat `{}`", path.display()))
+ })?;
let mtime = FileTime::from_last_modification_time(&meta);
*slot.0.lock().unwrap() = Some(mtime);
}
}
let old_fingerprint_json = paths::read(&loc.with_extension("json"))?;
- let old_fingerprint = serde_json::from_str(&old_fingerprint_json).chain_error(|| {
- internal(format!("failed to deserialize json"))
- })?;
+ let old_fingerprint = serde_json::from_str(&old_fingerprint_json)
+ .chain_err(|| {internal(format!("failed to deserialize json"))})?;
new_fingerprint.compare(&old_fingerprint)
}
fn log_compare(unit: &Unit, compare: &CargoResult<()>) {
- let mut e = match *compare {
+ let ce = match *compare {
Ok(..) => return,
- Err(ref e) => &**e,
+ Err(ref e) => e,
};
- info!("fingerprint error for {}: {}", unit.pkg, e);
- while let Some(cause) = e.cargo_cause() {
- info!(" cause: {}", cause);
- e = cause;
- }
- let mut e = e.cause();
- while let Some(cause) = e {
+ info!("fingerprint error for {}: {}", unit.pkg, ce);
+
+ for cause in ce.iter() {
info!(" cause: {}", cause);
- e = cause.cause();
}
}
Some(Ok(line)) => line,
_ => return Ok(None),
};
- let pos = line.find(": ").chain_error(|| {
+ let pos = line.find(": ").ok_or_else(|| {
internal(format!("dep-info not in an understood format: {}",
dep_info.display()))
})?;
while file.ends_with('\\') {
file.pop();
file.push(' ');
- file.push_str(deps.next().chain_error(|| {
+ file.push_str(deps.next().ok_or_else(|| {
internal("malformed dep-info format, trailing \\".to_string())
})?);
}
fn pkg_fingerprint(cx: &Context, pkg: &Package) -> CargoResult<String> {
let source_id = pkg.package_id().source_id();
let sources = cx.packages.sources();
- let source = sources.get(source_id).chain_error(|| {
+
+ let source = sources.get(source_id).ok_or_else(|| {
internal("missing package source")
})?;
source.fingerprint(pkg)
if self.active > 0 {
error = Some(human("build failed"));
- handle_error(&*e, &mut *cx.config.shell());
+ handle_error(e, &mut *cx.config.shell());
cx.config.shell().say(
"Build failed, waiting for other \
jobs to finish...", YELLOW)?;
}
-
- if error.is_none() {
+ else {
error = Some(e);
}
}
use core::{Package, PackageId, PackageSet, Target, Resolve};
use core::{Profile, Profiles, Workspace};
use core::shell::ColorConfig;
-use util::{self, CargoResult, ProcessBuilder, ProcessError, human, machine_message};
-use util::{Config, internal, ChainError, profile, join_paths, short_hash};
+use util::{self, ProcessBuilder, human, machine_message};
+use util::{Config, internal, profile, join_paths, short_hash};
+use util::errors::{CargoResult, CargoResultExt};
use util::Freshness;
use self::job::{Job, Work};
fn init(&self, _cx: &Context) {}
/// If execution succeeds, the ContinueBuild value indicates whether Cargo
/// should continue with the build process for this package.
- fn exec(&self, cmd: ProcessBuilder, _id: &PackageId) -> Result<(), ProcessError> {
+ fn exec(&self, cmd: ProcessBuilder, _id: &PackageId) -> CargoResult<()> {
cmd.exec()?;
Ok(())
}
_id: &PackageId,
handle_stdout: &mut FnMut(&str) -> CargoResult<()>,
handle_stderr: &mut FnMut(&str) -> CargoResult<()>)
- -> Result<(), ProcessError> {
+ -> CargoResult<()> {
cmd.exec_with_streaming(handle_stdout, handle_stderr)?;
Ok(())
}
}
for dst in &dsts {
if fs::metadata(dst).is_ok() {
- fs::remove_file(dst).chain_error(|| {
+ fs::remove_file(dst).chain_err(|| {
human(format!("Could not remove file: {}.", dst.display()))
})?;
}
}
Ok(())
}
- ).chain_error(|| {
+ ).chain_err(|| {
human(format!("Could not compile `{}`.", name))
})?;
} else {
- exec.exec(rustc, &package_id).chain_error(|| {
+ exec.exec(rustc, &package_id).map_err(|e| e.to_internal()).chain_err(|| {
human(format!("Could not compile `{}`.", name))
})?;
}
.to_str().unwrap()
.replace(&real_name, &crate_name));
if src.exists() && src.file_name() != dst.file_name() {
- fs::rename(&src, &dst).chain_error(|| {
+ fs::rename(&src, &dst).chain_err(|| {
internal(format!("could not rename crate {:?}", src))
})?;
}
if fs::metadata(&rustc_dep_info_loc).is_ok() {
info!("Renaming dep_info {:?} to {:?}", rustc_dep_info_loc, dep_info_loc);
- fs::rename(&rustc_dep_info_loc, &dep_info_loc).chain_error(|| {
+ fs::rename(&rustc_dep_info_loc, &dep_info_loc).chain_err(|| {
internal(format!("could not rename dep info: {:?}",
rustc_dep_info_loc))
})?;
pass_l_flag: bool,
current_id: &PackageId) -> CargoResult<()> {
for key in build_scripts.to_link.iter() {
- let output = build_state.get(key).chain_error(|| {
+ let output = build_state.get(key).ok_or_else(|| {
internal(format!("couldn't find build state for {}/{:?}",
key.0, key.1))
})?;
debug!("linking {} to {}", src.display(), dst.display());
if dst.exists() {
- fs::remove_file(&dst).chain_error(|| {
+ fs::remove_file(&dst).chain_err(|| {
human(format!("failed to remove: {}", dst.display()))
})?;
}
debug!("hard link failed {}. falling back to fs::copy", err);
fs::copy(src, dst).map(|_| ())
})
- .chain_error(|| {
+ .chain_err(|| {
human(format!("failed to link or copy `{}` to `{}`",
src.display(), dst.display()))
})?;
let mut search_path = env::split_paths(&search_path).collect::<Vec<_>>();
for id in build_scripts.plugins.iter() {
let key = (id.clone(), Kind::Host);
- let output = build_state.get(&key).chain_error(|| {
+ let output = build_state.get(&key).ok_or_else(|| {
internal(format!("couldn't find libs for plugin dep {}", id))
})?;
search_path.append(&mut filter_dynamic_search_path(output.library_paths.iter(),
}
}
state.running(&rustdoc);
- rustdoc.exec().chain_error(|| {
+ rustdoc.exec().chain_err(|| {
human(format!("Could not document `{}`.", name))
})
}))
use std::ffi::{OsString, OsStr};
use ops::{self, Compilation};
-use util::{self, CargoResult, CargoTestError, Test, ProcessError};
+use util::{self, CargoTestError, Test, ProcessError};
+use util::errors::{CargoResult, CargoErrorKind, CargoError};
use core::Workspace;
pub struct TestOptions<'a> {
shell.status("Running", cmd.to_string())
})?;
- if let Err(e) = cmd.exec() {
+ if let Err(CargoError(CargoErrorKind::ProcessErrorKind(e), .. )) = cmd.exec() {
errors.push(e);
if !options.no_fail_fast {
return Ok((Test::UnitTest(kind.clone(), test.clone()), errors))
config.shell().verbose(|shell| {
shell.status("Running", p.to_string())
})?;
- if let Err(e) = p.exec() {
+ if let Err(CargoError(CargoErrorKind::ProcessErrorKind(e), .. )) = p.exec() {
errors.push(e);
if !options.no_fail_fast {
return Ok((Test::Doc, errors));
use core::{Resolve, resolver, Workspace};
use core::resolver::WorkspaceResolve;
-use util::{CargoResult, ChainError, human, Filesystem};
+use util::{human, Filesystem};
+use util::errors::{CargoResult, CargoResultExt};
use util::toml as cargo_toml;
pub fn load_pkg_lockfile(ws: &Workspace) -> CargoResult<Option<Resolve>> {
let mut f = root.open_ro("Cargo.lock", ws.config(), "Cargo.lock file")?;
let mut s = String::new();
- f.read_to_string(&mut s).chain_error(|| {
+ f.read_to_string(&mut s).chain_err(|| {
human(format!("failed to read file: {}", f.path().display()))
})?;
- (|| {
- let resolve = cargo_toml::parse(&s, f.path(), ws.config())?;
+ (|| -> CargoResult<Option<Resolve>> {
+ let resolve : toml::Value = cargo_toml::parse(&s, f.path(), ws.config())?;
let v: resolver::EncodableResolve = resolve.try_into()?;
Ok(Some(v.into_resolve(ws)?))
- }).chain_error(|| {
+ })().chain_err(|| {
human(format!("failed to parse lock file at: {}", f.path().display()))
})
}
f.file().set_len(0)?;
f.write_all(out.as_bytes())?;
Ok(())
- }).chain_error(|| {
+ }).chain_err(|| {
human(format!("failed to write {}",
ws.root().join("Cargo.lock").display()))
})
use sources::{RegistrySource};
use util::config;
use util::paths;
-use util::{CargoResult, human, ChainError, ToUrl};
+use util::{human, ToUrl};
use util::config::{Config, ConfigValue, Location};
+use util::errors::{CargoResult, CargoResultExt};
use util::important_paths::find_root_manifest_for_wd;
pub struct RegistryConfig {
};
let api_host = {
let mut src = RegistrySource::remote(&sid, config);
- src.update().chain_error(|| {
+ src.update().chain_err(|| {
human(format!("failed to update {}", sid))
})?;
(src.config()?).unwrap().api
use core::resolver::{self, Resolve, Method};
use sources::PathSource;
use ops;
-use util::{profile, human, CargoResult, ChainError};
+use util::{profile, human};
+use util::errors::{CargoResult, CargoResultExt};
/// Resolve all dependencies for the workspace using the previous
/// lockfile as a guide if present.
for (path, definition) in paths {
let id = SourceId::for_path(&path)?;
let mut source = PathSource::new_recursive(&path, &id, ws.config());
- source.update().chain_error(|| {
+ source.update().chain_err(|| {
human(format!("failed to update path override `{}` \
(defined in `{}`)", path.display(),
definition.display()))
use core::{Source, SourceId};
use sources::ReplacedSource;
-use util::{CargoResult, Config, ChainError, human, ToUrl};
+use util::{Config, human, ToUrl};
use util::config::ConfigValue;
+use util::errors::{CargoResult, CargoResultExt};
pub struct SourceConfigMap<'cfg> {
cfgs: HashMap<String, SourceConfig>,
}
let mut srcs = srcs.into_iter();
- let src = srcs.next().chain_error(|| {
+ let src = srcs.next().ok_or_else(|| {
human(format!("no source URL specified for `source.{}`, need \
either `registry` or `local-registry` defined",
name))
fn url(cfg: &ConfigValue, key: &str) -> CargoResult<Url> {
let (url, path) = cfg.string(key)?;
- url.to_url().chain_error(|| {
+ url.to_url().chain_err(|| {
human(format!("configuration key `{}` specified an invalid \
URL (in {})", key, path.display()))
use core::{Package, PackageId, Summary, SourceId, Source, Dependency, Registry};
use sources::PathSource;
-use util::{CargoResult, human, ChainError, Config, Sha256};
+use util::{human, Config, Sha256};
+use util::errors::{CargoResult, CargoResultExt, CargoError};
use util::paths;
pub struct DirectorySource<'cfg> {
fn update(&mut self) -> CargoResult<()> {
self.packages.clear();
- let entries = self.root.read_dir().chain_error(|| {
+ let entries = self.root.read_dir().chain_err(|| {
human(format!("failed to read root of directory source: {}",
self.root.display()))
})?;
let pkg = src.root_package()?;
let cksum_file = path.join(".cargo-checksum.json");
- let cksum = paths::read(&path.join(cksum_file)).chain_error(|| {
+ let cksum = paths::read(&path.join(cksum_file)).chain_err(|| {
human(format!("failed to load checksum `.cargo-checksum.json` \
of {} v{}",
pkg.package_id().name(),
pkg.package_id().version()))
})?;
- let cksum: Checksum = serde_json::from_str(&cksum).chain_error(|| {
+ let cksum: Checksum = serde_json::from_str(&cksum)
+ .map_err(CargoError::from).chain_err(|| {
human(format!("failed to decode `.cargo-checksum.json` of \
{} v{}",
pkg.package_id().name(),
}
fn download(&mut self, id: &PackageId) -> CargoResult<Package> {
- self.packages.get(id).map(|p| &p.0).cloned().chain_error(|| {
+ self.packages.get(id).map(|p| &p.0).cloned().ok_or_else(|| {
human(format!("failed to find package with id: {}", id))
})
}
n => h.update(&buf[..n]),
}
}
- }).chain_error(|| {
+ })().chain_err(|| {
human(format!("failed to calculate checksum of: {}",
file.display()))
})?;
use url::Url;
use core::GitReference;
-use util::{CargoResult, ChainError, human, ToUrl, internal, Config, network};
+use util::{human, ToUrl, internal, Config, network};
+use util::errors::{CargoResult, CargoResultExt, CargoError};
#[derive(PartialEq, Clone, Debug)]
pub struct GitRevision(git2::Oid);
pub fn checkout(&self, into: &Path, cargo_config: &Config) -> CargoResult<GitDatabase> {
let repo = match git2::Repository::open(into) {
Ok(repo) => {
- self.fetch_into(&repo, cargo_config).chain_error(|| {
+ self.fetch_into(&repo, cargo_config).chain_err(|| {
human(format!("failed to fetch into {}", into.display()))
})?;
repo
}
Err(..) => {
- self.clone_into(into, cargo_config).chain_error(|| {
+ self.clone_into(into, cargo_config).chain_err(|| {
human(format!("failed to clone into: {}", into.display()))
})?
}
}
fs::create_dir_all(dst)?;
let repo = git2::Repository::init_bare(dst)?;
- fetch(&repo, &url, "refs/heads/*:refs/heads/*", cargo_config)?;
+ fetch(&repo, &url, "refs/heads/*:refs/heads/*", cargo_config)?;
Ok(repo)
}
}
pub fn rev_for(&self, reference: &GitReference) -> CargoResult<GitRevision> {
let id = match *reference {
GitReference::Tag(ref s) => {
- (|| {
+ (|| -> CargoResult<git2::Oid> {
let refname = format!("refs/tags/{}", s);
let id = self.repo.refname_to_id(&refname)?;
let obj = self.repo.find_object(id, None)?;
let obj = obj.peel(ObjectType::Commit)?;
Ok(obj.id())
- }).chain_error(|| {
+ })().chain_err(|| {
human(format!("failed to find tag `{}`", s))
})?
}
GitReference::Branch(ref s) => {
(|| {
let b = self.repo.find_branch(s, git2::BranchType::Local)?;
- b.get().target().chain_error(|| {
+ b.get().target().ok_or_else(|| {
human(format!("branch `{}` did not have a target", s))
})
- }).chain_error(|| {
+ })().chain_err(|| {
human(format!("failed to find branch `{}`", s))
})?
}
fn clone_repo(source: &Path, into: &Path) -> CargoResult<git2::Repository> {
let dirname = into.parent().unwrap();
- fs::create_dir_all(&dirname).chain_error(|| {
+ fs::create_dir_all(&dirname).map_err(CargoError::from).chain_err(|| {
human(format!("Couldn't mkdir {}", dirname.display()))
})?;
if fs::metadata(&into).is_ok() {
- fs::remove_dir_all(into).chain_error(|| {
+ fs::remove_dir_all(into).map_err(CargoError::from).chain_err(|| {
human(format!("Couldn't rmdir {}", into.display()))
})?;
}
let url = source.to_url()?;
let url = url.to_string();
- let repo = git2::Repository::clone(&url, into).chain_error(|| {
- internal(format!("failed to clone {} into {}", source.display(),
+ let repo = git2::Repository::clone(&url, into)
+ .map_err(CargoError::from)
+ .chain_err(|| {
+ internal(format!("failed to clone {} into {}", source.display(),
into.display()))
})?;
Ok(repo)
let ok_file = self.location.join(".cargo-ok");
let _ = fs::remove_file(&ok_file);
info!("reset {} to {}", self.repo.path().display(), self.revision);
- let object = self.repo.find_object(self.revision.0, None)?;
- self.repo.reset(&object, git2::ResetType::Hard, None)?;
+ self.repo.find_object(self.revision.0, None)
+ .and_then(|obj| {self.repo.reset(&obj, git2::ResetType::Hard, None)})?;
File::create(ok_file)?;
Ok(())
}
info!("update submodules for: {:?}", repo.workdir().unwrap());
for mut child in repo.submodules()?.into_iter() {
- update_submodule(repo, &mut child, cargo_config).chain_error(|| {
+ update_submodule(repo, &mut child, cargo_config).chain_err(|| {
human(format!("failed to update submodule `{}`",
child.name().unwrap_or("")))
})?;
child: &mut git2::Submodule,
cargo_config: &Config) -> CargoResult<()> {
child.init(false)?;
- let url = child.url().chain_error(|| {
+ let url = child.url().ok_or_else(|| {
internal("non-utf8 url for submodule")
})?;
// Fetch data from origin and reset to the head commit
let refspec = "refs/heads/*:refs/heads/*";
- fetch(&repo, url, refspec, cargo_config).chain_error(|| {
+ fetch(&repo, url, refspec, cargo_config).chain_err(|| {
internal(format!("failed to fetch submodule `{}` from {}",
child.name().unwrap_or(""), url))
})?;
- let obj = repo.find_object(head, None)?;
- repo.reset(&obj, git2::ResetType::Hard, None)?;
+ repo.find_object(head, None)
+ .and_then(|obj| { repo.reset(&obj, git2::ResetType::Hard, None)})?;
update_submodules(&repo, cargo_config)
}
}
// In the case of an authentication failure (where we tried something) then
// we try to give a more helpful error message about precisely what we
// tried.
- res.chain_error(|| {
+ res.chain_err(|| {
let mut msg = "failed to authenticate when downloading \
repository".to_string();
if !ssh_agent_attempts.is_empty() {
network::with_retry(config, || {
remote.fetch(&[refspec], Some(&mut opts), None)
+ .map_err(network::NetworkError::from)
})?;
Ok(())
})
use core::{Package, PackageId, Summary, SourceId, Source, Dependency, Registry};
use ops;
-use util::{self, CargoResult, internal, internal_error, human, ChainError};
+use util::{self, CargoResult, internal, internal_error, human};
use util::Config;
pub struct PathSource<'cfg> {
-> CargoResult<Vec<PathBuf>> {
warn!("list_files_git {}", pkg.package_id());
let index = repo.index()?;
- let root = repo.workdir().chain_error(|| {
+ let root = repo.workdir().ok_or_else(|| {
internal_error("Can't list files on a bare repository.", "")
})?;
let pkg_path = pkg.root();
if is_dir.unwrap_or_else(|| file_path.is_dir()) {
warn!(" found submodule {}", file_path.display());
let rel = util::without_prefix(&file_path, root).unwrap();
- let rel = rel.to_str().chain_error(|| {
+ let rel = rel.to_str().ok_or_else(|| {
human(format!("invalid utf-8 filename: {}", rel.display()))
})?;
// Git submodules are currently only named through `/` path
use core::{SourceId, Summary, PackageId, Registry};
use sources::registry::{RegistryPackage, RegistryDependency, INDEX_LOCK};
use sources::registry::RegistryData;
-use util::{CargoResult, ChainError, internal, Filesystem, Config};
+use util::{CargoResult, internal, Filesystem, Config};
use util::human;
pub struct RegistryIndex<'cfg> {
}
// Ok, we're missing the key, so parse the index file to load it.
self.summaries(pkg.name(), load)?;
- self.hashes.get(&key).chain_error(|| {
+ self.hashes.get(&key).ok_or_else(|| {
internal(format!("no hash listed for {}", pkg))
}).map(|s| s.clone())
}
use sources::registry::{RegistryData, RegistryConfig};
use util::FileLock;
use util::paths;
-use util::{Config, CargoResult, ChainError, human, Sha256, Filesystem};
+use util::{Config, human, Sha256, Filesystem};
+use util::errors::{CargoResult, CargoResultExt};
pub struct LocalRegistry<'cfg> {
index_path: Filesystem,
let mut state = Sha256::new();
let mut buf = [0; 64 * 1024];
loop {
- let n = crate_file.read(&mut buf).chain_error(|| {
+ let n = crate_file.read(&mut buf).chain_err(|| {
human(format!("failed to read `{}`", crate_file.path().display()))
})?;
if n == 0 {
use core::{Source, SourceId, PackageId, Package, Summary, Registry};
use core::dependency::Dependency;
use sources::PathSource;
-use util::{CargoResult, Config, internal, ChainError, FileLock, Filesystem};
+use util::{CargoResult, Config, internal, FileLock, Filesystem};
+use util::errors::CargoResultExt;
use util::hex;
const INDEX_LOCK: &'static str = ".cargo-index-lock";
fn download(&mut self, package: &PackageId) -> CargoResult<Package> {
let hash = self.index.hash(package, &mut *self.ops)?;
let path = self.ops.download(package, &hash)?;
- let path = self.unpack_package(package, &path).chain_error(|| {
+ let path = self.unpack_package(package, &path).chain_err(|| {
internal(format!("failed to unpack package `{}`", package))
})?;
let mut src = PathSource::new(&path, &self.source_id, self.config);
use sources::registry::{RegistryData, RegistryConfig, INDEX_LOCK};
use util::network;
use util::{FileLock, Filesystem, LazyCell};
-use util::{Config, CargoResult, ChainError, human, Sha256, ToUrl};
-use util::errors::HttpError;
+use util::{Config, human, Sha256, ToUrl};
+use util::errors::{CargoResult, CargoResultExt};
pub struct RemoteRegistry<'cfg> {
index_path: Filesystem,
// git fetch origin master
let url = self.source_id.url().to_string();
let refspec = "refs/heads/master:refs/remotes/origin/master";
- git::fetch(&repo, &url, refspec, self.config).chain_error(|| {
+ git::fetch(&repo, &url, refspec, self.config).chain_err(|| {
human(format!("failed to fetch `{}`", url))
})?;
}
+
self.head.set(None);
*self.tree.borrow_mut() = None;
Ok(())
let code = handle.response_code()?;
if code != 200 && code != 0 {
let url = handle.effective_url()?.unwrap_or(&url);
- Err(HttpError::Not200(code, url.to_string()))
+ Err(network::NetworkErrorKind::HttpNot200(code, url.to_string()).into())
} else {
Ok(())
}
use core::{Source, Registry, PackageId, Package, Dependency, Summary, SourceId};
-use util::{CargoResult, ChainError, human};
+use util::{CargoResult, human};
+use util::errors::CargoResultExt;
pub struct ReplacedSource<'cfg> {
to_replace: SourceId,
impl<'cfg> Registry for ReplacedSource<'cfg> {
fn query(&mut self, dep: &Dependency) -> CargoResult<Vec<Summary>> {
let dep = dep.clone().map_source(&self.to_replace, &self.replace_with);
- let ret = self.inner.query(&dep).chain_error(|| {
+ let ret = self.inner.query(&dep).chain_err(|| {
human(format!("failed to query replaced source `{}`",
self.to_replace))
})?;
}
fn update(&mut self) -> CargoResult<()> {
- self.inner.update().chain_error(|| {
+ self.inner.update().chain_err(|| {
human(format!("failed to update replaced source `{}`",
self.to_replace))
})
fn download(&mut self, id: &PackageId) -> CargoResult<Package> {
let id = id.with_source_id(&self.replace_with);
- let pkg = self.inner.download(&id).chain_error(|| {
+ let pkg = self.inner.download(&id).chain_err(|| {
human(format!("failed to download replaced source `{}`",
self.to_replace))
})?;
}
impl FromStr for Cfg {
- type Err = Box<CargoError>;
+ type Err = CargoError;
fn from_str(s: &str) -> CargoResult<Cfg> {
let mut p = Parser::new(s);
}
impl FromStr for CfgExpr {
- type Err = Box<CargoError>;
+ type Err = CargoError;
fn from_str(s: &str) -> CargoResult<CfgExpr> {
let mut p = Parser::new(s);
use toml;
use core::shell::{Verbosity, ColorConfig};
use core::MultiShell;
-use util::{CargoResult, CargoError, ChainError, Rustc, internal, human};
+use util::{CargoResult, CargoError, Rustc, internal, human};
+use util::errors::CargoResultExt;
use util::{Filesystem, LazyCell};
use util::paths;
pub fn default() -> CargoResult<Config> {
let shell = ::shell(Verbosity::Verbose, ColorConfig::Auto);
- let cwd = env::current_dir().chain_error(|| {
+ let cwd = env::current_dir().chain_err(|| {
human("couldn't get the current directory of the process")
})?;
- let homedir = homedir(&cwd).chain_error(|| {
+ let homedir = homedir(&cwd).ok_or_else(|| {
human("Cargo couldn't find your home directory. \
This probably means that $HOME was not set.")
})?;
pub fn cargo_exe(&self) -> CargoResult<&Path> {
self.cargo_exe.get_or_try_init(||
env::current_exe().and_then(|path| path.canonicalize())
- .chain_error(|| {
+ .chain_err(|| {
human("couldn't get the path to cargo executable")
})
).map(AsRef::as_ref)
}
fn get_env<V: FromStr>(&self, key: &str) -> CargoResult<Option<Value<V>>>
- where Box<CargoError>: From<V::Err>
+ where CargoError: From<V::Err>
{
let key = key.replace(".", "_")
.replace("-", "_")
walk_tree(&self.cwd, |mut file, path| {
let mut contents = String::new();
- file.read_to_string(&mut contents).chain_error(|| {
+ file.read_to_string(&mut contents).chain_err(|| {
human(format!("failed to read configuration file `{}`",
path.display()))
})?;
let toml = cargo_toml::parse(&contents,
&path,
- self).chain_error(|| {
+ self).chain_err(|| {
human(format!("could not parse TOML configuration in `{}`",
path.display()))
})?;
- let value = CV::from_toml(&path, toml).chain_error(|| {
+ let value = CV::from_toml(&path, toml).chain_err(|| {
human(format!("failed to load TOML configuration from `{}`",
path.display()))
})?;
- cfg.merge(value).chain_error(|| {
+ cfg.merge(value).chain_err(|| {
human(format!("failed to merge configuration at `{}`",
path.display()))
})?;
Ok(())
- }).chain_error(|| human("Couldn't load Cargo configuration"))?;
+ }).chain_err(|| human("Couldn't load Cargo configuration"))?;
match cfg {
}
toml::Value::Table(val) => {
Ok(CV::Table(val.into_iter().map(|(key, value)| {
- let value = CV::from_toml(path, value).chain_error(|| {
+ let value = CV::from_toml(path, value).chain_err(|| {
human(format!("failed to parse key `{}`", key))
})?;
Ok((key, value))
Occupied(mut entry) => {
let path = value.definition_path().to_path_buf();
let entry = entry.get_mut();
- entry.merge(value).chain_error(|| {
+ entry.merge(value).chain_err(|| {
human(format!("failed to merge key `{}` between \
files:\n \
file 1: {}\n \
// Once we're done, also be sure to walk the home directory even if it's not
// in our history to be sure we pick up that standard location for
// information.
- let home = homedir(pwd).chain_error(|| {
+ let home = homedir(pwd).ok_or_else(|| {
human("Cargo couldn't find your home directory. \
This probably means that $HOME was not set.")
})?;
use std::error::Error;
-use std::ffi;
use std::fmt;
use std::io;
use std::num;
use std::string;
use core::TargetKind;
+use util::network::{NetworkError, NetworkErrorKind};
use curl;
use git2;
-use glob;
use semver;
use serde_json;
use term;
use toml;
-use url;
-pub type CargoResult<T> = Result<T, Box<CargoError>>;
-
-// =============================================================================
-// CargoError trait
-
-pub trait CargoError: Error + Send + 'static {
- fn is_human(&self) -> bool { false }
- fn cargo_cause(&self) -> Option<&CargoError>{ None }
- fn as_error(&self) -> &Error where Self: Sized { self as &Error }
-}
-
-impl Error for Box<CargoError> {
- fn description(&self) -> &str { (**self).description() }
- fn cause(&self) -> Option<&Error> { (**self).cause() }
-}
-
-impl CargoError for Box<CargoError> {
- fn is_human(&self) -> bool { (**self).is_human() }
- fn cargo_cause(&self) -> Option<&CargoError> { (**self).cargo_cause() }
-}
-
-// =============================================================================
-// Chaining errors
-
-pub trait ChainError<T> {
- fn chain_error<E, F>(self, callback: F) -> CargoResult<T>
- where E: CargoError, F: FnOnce() -> E;
-}
-
-#[derive(Debug)]
-struct ChainedError<E> {
- error: E,
- cause: Box<CargoError>,
-}
-
-impl<'a, T, F> ChainError<T> for F where F: FnOnce() -> CargoResult<T> {
- fn chain_error<E, C>(self, callback: C) -> CargoResult<T>
- where E: CargoError, C: FnOnce() -> E {
- self().chain_error(callback)
+error_chain! {
+ types {
+ CargoError, CargoErrorKind, CargoResultExt, CargoResult;
}
-}
-impl<T, E: CargoError + 'static> ChainError<T> for Result<T, E> {
- fn chain_error<E2: 'static, C>(self, callback: C) -> CargoResult<T>
- where E2: CargoError, C: FnOnce() -> E2 {
- self.map_err(move |err| {
- Box::new(ChainedError {
- error: callback(),
- cause: Box::new(err),
- }) as Box<CargoError>
- })
+ links {
+ Network(NetworkError, NetworkErrorKind);
}
-}
-impl<T> ChainError<T> for Box<CargoError> {
- fn chain_error<E2, C>(self, callback: C) -> CargoResult<T>
- where E2: CargoError, C: FnOnce() -> E2 {
- Err(Box::new(ChainedError {
- error: callback(),
- cause: self,
- }))
+ foreign_links {
+ ParseSemver(semver::ReqParseError);
+ Io(io::Error);
+ SerdeJson(serde_json::Error);
+ TomlSer(toml::ser::Error);
+ TomlDe(toml::de::Error);
+ Term(term::Error);
+ ParseInt(num::ParseIntError);
+ ParseBool(str::ParseBoolError);
+ Parse(string::ParseError);
+ Git(git2::Error);
+ Curl(curl::Error);
}
-}
-impl<T> ChainError<T> for Option<T> {
- fn chain_error<E: 'static, C>(self, callback: C) -> CargoResult<T>
- where E: CargoError, C: FnOnce() -> E {
- match self {
- Some(t) => Ok(t),
- None => Err(Box::new(callback())),
+ errors {
+ Internal(description: String, details: Option<String>){
+ description(&description)
+ display("{}", &description)
+ }
+ ProcessErrorKind(proc_err: ProcessError) {
+ description(&proc_err.desc)
+ display("{}", &proc_err.desc)
+ }
+ CargoTestErrorKind(test_err: CargoTestError) {
+ description(&test_err.desc)
+ display("{}", &test_err.desc)
}
}
}
-impl<E: Error> Error for ChainedError<E> {
- fn description(&self) -> &str { self.error.description() }
-}
+impl CargoError {
+ pub fn to_internal(self) -> Self {
+ CargoError(CargoErrorKind::Internal(self.description().to_string(), None), self.1)
+ }
-impl<E: fmt::Display> fmt::Display for ChainedError<E> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Display::fmt(&self.error, f)
+ fn is_human(&self) -> bool {
+ match &self.0 {
+ &CargoErrorKind::Msg(_) => true,
+ &CargoErrorKind::TomlSer(_) => true,
+ &CargoErrorKind::TomlDe(_) => true,
+ &CargoErrorKind::Curl(_) => true,
+ &CargoErrorKind::Network(ref net_err) => {
+ match net_err {
+ &NetworkErrorKind::HttpNot200(_, _) => true,
+ &NetworkErrorKind::Curl(_) => true,
+ _ => false
+ }
+ },
+ _ => false
+ }
}
}
-impl<E: CargoError> CargoError for ChainedError<E> {
- fn is_human(&self) -> bool { self.error.is_human() }
- fn cargo_cause(&self) -> Option<&CargoError> { Some(&*self.cause) }
-}
// =============================================================================
// Process errors
-
+#[derive(Debug)]
pub struct ProcessError {
pub desc: String,
pub exit: Option<ExitStatus>,
pub output: Option<Output>,
- cause: Option<Box<CargoError>>,
-}
-
-impl Error for ProcessError {
- fn description(&self) -> &str { &self.desc }
- fn cause(&self) -> Option<&Error> {
- self.cause.as_ref().map(|e| e.as_error())
- }
-}
-
-impl fmt::Display for ProcessError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Display::fmt(&self.desc, f)
- }
-}
-impl fmt::Debug for ProcessError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Display::fmt(self, f)
- }
}
// =============================================================================
// Cargo test errors.
/// Error when testcases fail
+#[derive(Debug)]
pub struct CargoTestError {
pub test: Test,
pub desc: String,
pub causes: Vec<ProcessError>,
}
+#[derive(Debug)]
pub enum Test {
Multiple,
Doc,
}
}
-impl fmt::Display for CargoTestError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Display::fmt(&self.desc, f)
- }
-}
-
-impl fmt::Debug for CargoTestError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Display::fmt(self, f)
- }
-}
-
-impl Error for CargoTestError {
- fn description(&self) -> &str { &self.desc }
- fn cause(&self) -> Option<&Error> {
- self.causes.get(0).map(|s| s as &Error)
- }
-}
-
-
-// =============================================================================
-// Concrete errors
-
-struct ConcreteCargoError {
- description: String,
- detail: Option<String>,
- cause: Option<Box<Error+Send>>,
- is_human: bool,
-}
-
-impl fmt::Display for ConcreteCargoError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}", self.description)?;
- if let Some(ref s) = self.detail {
- write!(f, " ({})", s)?;
- }
- Ok(())
- }
-}
-impl fmt::Debug for ConcreteCargoError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Display::fmt(self, f)
- }
-}
-
-impl Error for ConcreteCargoError {
- fn description(&self) -> &str { &self.description }
- fn cause(&self) -> Option<&Error> {
- self.cause.as_ref().map(|c| {
- let e: &Error = &**c; e
- })
- }
-}
-
-impl CargoError for ConcreteCargoError {
- fn is_human(&self) -> bool {
- self.is_human
- }
-}
-
-// =============================================================================
-// Human errors
-
-#[derive(Debug)]
-pub struct Human<E>(pub E);
-
-impl<E: Error> Error for Human<E> {
- fn description(&self) -> &str { self.0.description() }
- fn cause(&self) -> Option<&Error> { self.0.cause() }
-}
-
-impl<E: fmt::Display> fmt::Display for Human<E> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Display::fmt(&self.0, f)
- }
-}
-
-impl<E: CargoError> CargoError for Human<E> {
- fn is_human(&self) -> bool { true }
- fn cargo_cause(&self) -> Option<&CargoError> { self.0.cargo_cause() }
-}
-
// =============================================================================
// CLI errors
#[derive(Debug)]
pub struct CliError {
- pub error: Option<Box<CargoError>>,
+ pub error: Option<CargoError>,
pub unknown: bool,
pub exit_code: i32
}
}
impl CliError {
- pub fn new(error: Box<CargoError>, code: i32) -> CliError {
- let human = error.is_human();
+ pub fn new(error: CargoError, code: i32) -> CliError {
+ let human = &error.is_human();
CliError { error: Some(error), exit_code: code, unknown: !human }
}
}
}
-impl From<Box<CargoError>> for CliError {
- fn from(err: Box<CargoError>) -> CliError {
+impl From<CargoError> for CliError {
+ fn from(err: CargoError) -> CliError {
CliError::new(err, 101)
}
}
-// =============================================================================
-// NetworkError trait
-
-pub trait NetworkError: CargoError {
- fn maybe_spurious(&self) -> bool;
-}
-
-impl NetworkError for git2::Error {
- fn maybe_spurious(&self) -> bool {
- match self.class() {
- git2::ErrorClass::Net |
- git2::ErrorClass::Os => true,
- _ => false
- }
- }
-}
-
-impl NetworkError for curl::Error {
- fn maybe_spurious(&self) -> bool {
- self.is_couldnt_connect() ||
- self.is_couldnt_resolve_proxy() ||
- self.is_couldnt_resolve_host() ||
- self.is_operation_timedout() ||
- self.is_recv_error()
- }
-}
-
-#[derive(Debug)]
-pub enum HttpError {
- Not200(u32, String),
- Curl(curl::Error),
-}
-
-impl fmt::Display for HttpError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- HttpError::Not200(code, ref url) => {
- write!(f, "failed to get 200 response from `{}`, got {}",
- url, code)
- }
- HttpError::Curl(ref e) => e.fmt(f),
- }
- }
-}
-
-impl Error for HttpError {
- fn description(&self) -> &str {
- match *self {
- HttpError::Not200(..) => "failed to get a 200 response",
- HttpError::Curl(ref e) => e.description(),
- }
- }
-
- fn cause(&self) -> Option<&Error> {
- match *self {
- HttpError::Not200(..) => None,
- HttpError::Curl(ref e) => e.cause(),
- }
- }
-}
-
-impl CargoError for HttpError {
- fn is_human(&self) -> bool {
- true
- }
-}
-
-impl NetworkError for HttpError {
- fn maybe_spurious(&self) -> bool {
- match *self {
- HttpError::Not200(code, ref _url) => {
- 500 <= code && code < 600
- }
- HttpError::Curl(ref e) => e.maybe_spurious(),
- }
- }
-}
-
-impl From<curl::Error> for HttpError {
- fn from(err: curl::Error) -> HttpError {
- HttpError::Curl(err)
- }
-}
-
-// =============================================================================
-// various impls
-
-macro_rules! from_error {
- ($($p:ty,)*) => (
- $(impl From<$p> for Box<CargoError> {
- fn from(t: $p) -> Box<CargoError> { Box::new(t) }
- })*
- )
-}
-
-from_error! {
- semver::ReqParseError,
- io::Error,
- ProcessError,
- git2::Error,
- serde_json::Error,
- curl::Error,
- CliError,
- url::ParseError,
- toml::ser::Error,
- toml::de::Error,
- ffi::NulError,
- term::Error,
- num::ParseIntError,
- str::ParseBoolError,
- glob::PatternError,
- glob::GlobError,
-}
-
-impl From<string::ParseError> for Box<CargoError> {
- fn from(t: string::ParseError) -> Box<CargoError> {
- match t {}
- }
-}
-
-impl<E: CargoError> From<Human<E>> for Box<CargoError> {
- fn from(t: Human<E>) -> Box<CargoError> { Box::new(t) }
-}
-
-impl CargoError for semver::ReqParseError {}
-impl CargoError for io::Error {}
-impl CargoError for git2::Error {}
-impl CargoError for serde_json::Error {}
-impl CargoError for curl::Error {}
-impl CargoError for ProcessError {}
-impl CargoError for CargoTestError {}
-impl CargoError for CliError {}
-impl CargoError for toml::ser::Error {
- fn is_human(&self) -> bool { true }
-}
-impl CargoError for toml::de::Error {
- fn is_human(&self) -> bool { true }
-}
-impl CargoError for url::ParseError {}
-impl CargoError for ffi::NulError {}
-impl CargoError for term::Error {}
-impl CargoError for num::ParseIntError {}
-impl CargoError for str::ParseBoolError {}
-impl CargoError for glob::PatternError {}
-impl CargoError for glob::GlobError {}
// =============================================================================
// Construction helpers
pub fn process_error(msg: &str,
- cause: Option<Box<CargoError>>,
status: Option<&ExitStatus>,
output: Option<&Output>) -> ProcessError
{
desc: desc,
exit: status.cloned(),
output: output.cloned(),
- cause: cause,
};
#[cfg(unix)]
}
}
-pub fn internal_error(error: &str, detail: &str) -> Box<CargoError> {
- Box::new(ConcreteCargoError {
- description: error.to_string(),
- detail: Some(detail.to_string()),
- cause: None,
- is_human: false
- })
+pub fn internal_error(error: &str, detail: &str) -> CargoError {
+ CargoErrorKind::Internal(error.to_string(), Some(detail.to_string())).into()
}
-pub fn internal<S: fmt::Display>(error: S) -> Box<CargoError> {
+pub fn internal<S: fmt::Display>(error: S) -> CargoError {
_internal(&error)
}
-fn _internal(error: &fmt::Display) -> Box<CargoError> {
- Box::new(ConcreteCargoError {
- description: error.to_string(),
- detail: None,
- cause: None,
- is_human: false
- })
+fn _internal(error: &fmt::Display) -> CargoError {
+ CargoErrorKind::Internal(error.to_string(), None).into()
}
-pub fn human<S: fmt::Display>(error: S) -> Box<CargoError> {
+pub fn human<S: fmt::Display>(error: S) -> CargoError {
_human(&error)
}
-fn _human(error: &fmt::Display) -> Box<CargoError> {
- Box::new(ConcreteCargoError {
- description: error.to_string(),
- detail: None,
- cause: None,
- is_human: true
- })
-}
-
-pub fn caused_human<S, E>(error: S, cause: E) -> Box<CargoError>
- where S: fmt::Display,
- E: Error + Send + 'static
-{
- Box::new(ConcreteCargoError {
- description: error.to_string(),
- detail: None,
- cause: Some(Box::new(cause)),
- is_human: true
- })
+fn _human(error: &fmt::Display) -> CargoError {
+ CargoErrorKind::Msg(error.to_string()).into()
}
#[allow(unused_imports)]
use libc;
-use util::{CargoResult, ChainError, Config, human};
+use util::{Config, human};
+use util::errors::{CargoResult, CargoResultExt};
pub struct FileLock {
f: Option<File>,
} else {
Err(e)
}
- }).chain_error(|| {
+ }).chain_err(|| {
human(format!("failed to open: {}", path.display()))
})?;
match state {
Err(e) => {
if e.raw_os_error() != lock_contended_error().raw_os_error() {
- return Err(human(e)).chain_error(|| {
+ return Err(human(e)).chain_err(|| {
human(format!("failed to lock file: {}", path.display()))
})
}
let msg = format!("waiting for file lock on {}", msg);
config.shell().err().say_status("Blocking", &msg, CYAN, true)?;
- return block().chain_error(|| {
+ return block().chain_err(|| {
human(format!("failed to lock file: {}", path.display()))
});
pub use self::cfg::{Cfg, CfgExpr};
pub use self::config::{Config, ConfigValue, homedir};
pub use self::dependency_queue::{DependencyQueue, Fresh, Dirty, Freshness};
-pub use self::errors::{CargoResult, CargoError, Test, ChainError, CliResult};
+pub use self::errors::{CargoResult, CargoResultExt, CargoError, CargoErrorKind, Test, CliResult};
pub use self::errors::{CliError, ProcessError, CargoTestError};
-pub use self::errors::{Human, caused_human};
pub use self::errors::{process_error, internal_error, internal, human};
pub use self::flock::{FileLock, Filesystem};
pub use self::graph::Graph;
-use util::{CargoResult, Config, errors};
+use util::Config;
+use util::errors::CargoResult;
+
+use curl;
+use git2;
+
+// =============================================================================
+// NetworkError chain
+error_chain!{
+ types {
+ NetworkError, NetworkErrorKind, NetworkResultExt, NetworkResult;
+ }
+
+ foreign_links {
+ Git(git2::Error);
+ Curl(curl::Error);
+ }
+
+ errors {
+ HttpNot200(code: u32, url: String) {
+ description("failed to get a 200 response")
+ display("failed to get 200 response from `{}`, got {}", url, code)
+ }
+ }
+}
+
+impl NetworkError {
+ pub fn maybe_spurious(&self) -> bool {
+ match &self.0 {
+ &NetworkErrorKind::Msg(_) => false,
+ &NetworkErrorKind::Git(ref git_err) => {
+ match git_err.class() {
+ git2::ErrorClass::Net |
+ git2::ErrorClass::Os => true,
+ _ => false
+ }
+ }
+ &NetworkErrorKind::Curl(ref curl_err) => {
+ curl_err.is_couldnt_connect() ||
+ curl_err.is_couldnt_resolve_proxy() ||
+ curl_err.is_couldnt_resolve_host() ||
+ curl_err.is_operation_timedout() ||
+ curl_err.is_recv_error()
+ }
+ &NetworkErrorKind::HttpNot200(code, ref _url) => {
+ 500 <= code && code < 600
+ }
+ }
+ }
+}
/// Wrapper method for network call retry logic.
///
/// use util::network;
/// cargo_result = network.with_retry(&config, || something.download());
/// ```
-pub fn with_retry<T, E, F>(config: &Config, mut callback: F) -> CargoResult<T>
- where F: FnMut() -> Result<T, E>,
- E: errors::NetworkError
+pub fn with_retry<T, F>(config: &Config, mut callback: F) -> CargoResult<T>
+ where F: FnMut() -> NetworkResult<T>
{
let mut remaining = config.net_retry()?;
loop {
config.shell().warn(msg)?;
remaining -= 1;
}
- Err(e) => return Err(Box::new(e)),
+ //todo impl from
+ Err(e) => return Err(e.into()),
}
}
}
#[test]
fn with_retry_repeats_the_call_then_works() {
-
- use std::error::Error;
- use util::human;
- use std::fmt;
-
- #[derive(Debug)]
- struct NetworkRetryError {
- error: Box<errors::CargoError>,
- }
-
- impl Error for NetworkRetryError {
- fn description(&self) -> &str {
- self.error.description()
- }
- fn cause(&self) -> Option<&Error> {
- self.error.cause()
- }
- }
-
- impl NetworkRetryError {
- fn new(error: &str) -> NetworkRetryError {
- let error = human(error.to_string());
- NetworkRetryError {
- error: error,
- }
- }
- }
-
- impl fmt::Display for NetworkRetryError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Display::fmt(&self.error, f)
- }
- }
-
- impl errors::CargoError for NetworkRetryError {
- fn is_human(&self) -> bool {
- false
- }
- }
-
- impl errors::NetworkError for NetworkRetryError {
- fn maybe_spurious(&self) -> bool {
- true
- }
- }
-
- let error1 = NetworkRetryError::new("one");
- let error2 = NetworkRetryError::new("two");
- let mut results: Vec<Result<(), NetworkRetryError>> = vec![Ok(()),
- Err(error1), Err(error2)];
+ //Error HTTP codes (5xx) are considered maybe_spurious and will prompt retry
+ let error1 = NetworkErrorKind::HttpNot200(501, "Uri".to_string()).into();
+ let error2 = NetworkErrorKind::HttpNot200(502, "Uri".to_string()).into();
+ let mut results: Vec<NetworkResult<()>> = vec![Ok(()), Err(error1), Err(error2)];
let config = Config::default().unwrap();
let result = with_retry(&config, || results.pop().unwrap());
assert_eq!(result.unwrap(), ())
use std::io::prelude::*;
use std::path::{Path, PathBuf, Component};
-use util::{human, internal, CargoResult, ChainError};
+use util::{human, internal, CargoResult};
+use util::errors::CargoResultExt;
pub fn join_paths<T: AsRef<OsStr>>(paths: &[T], env: &str) -> CargoResult<OsString> {
env::join_paths(paths.iter()).or_else(|e| {
let paths = paths.iter().map(Path::new).collect::<Vec<_>>();
- internal(format!("failed to join path array: {:?}", paths)).chain_error(|| {
+ Err(internal(format!("failed to join path array: {:?}", paths))).chain_err(|| {
human(format!("failed to join search paths together: {}\n\
Does ${} have an unterminated quote character?",
e, env))
let mut f = File::open(path)?;
f.read_to_string(&mut ret)?;
Ok(ret)
- })().map_err(human).chain_error(|| {
+ })().map_err(human).chain_err(|| {
human(format!("failed to read `{}`", path.display()))
})
}
let mut f = File::open(path)?;
f.read_to_end(&mut ret)?;
Ok(ret)
- })().map_err(human).chain_error(|| {
+ })().map_err(human).chain_err(|| {
human(format!("failed to read `{}`", path.display()))
})
}
let mut f = File::create(path)?;
f.write_all(contents)?;
Ok(())
- })().map_err(human).chain_error(|| {
+ })().map_err(human).chain_err(|| {
human(format!("failed to write `{}`", path.display()))
})
}
f.write_all(contents)?;
Ok(())
- }).chain_error(|| {
+ })().chain_err(|| {
internal(format!("failed to write `{}`", path.display()))
})
}
use std::path::Path;
use std::process::{Command, Stdio, Output};
-use util::{CargoResult, ProcessError, process_error, read2};
+use util::{CargoResult, CargoResultExt, CargoError, process_error, read2};
+use util::errors::CargoErrorKind;
use shell_escape::escape;
#[derive(Clone, PartialEq, Debug)]
pub fn get_envs(&self) -> &HashMap<String, Option<OsString>> { &self.env }
- pub fn exec(&self) -> Result<(), ProcessError> {
+ pub fn exec(&self) -> CargoResult<()> {
let mut command = self.build_command();
- let exit = command.status().map_err(|e| {
- process_error(&format!("could not execute process `{}`",
- self.debug_string()),
- Some(Box::new(e)), None, None)
+ let exit = command.status().chain_err(|| {
+ CargoErrorKind::ProcessErrorKind(
+ process_error(&format!("could not execute process `{}`",
+ self.debug_string()), None, None))
})?;
if exit.success() {
Ok(())
} else {
- Err(process_error(&format!("process didn't exit successfully: `{}`",
+ Err(CargoErrorKind::ProcessErrorKind(process_error(&format!("process didn't exit successfully: `{}`",
self.debug_string()),
- None, Some(&exit), None))
+ Some(&exit), None)).into())
}
}
#[cfg(unix)]
- pub fn exec_replace(&self) -> Result<(), ProcessError> {
+ pub fn exec_replace(&self) -> CargoResult<()> {
use std::os::unix::process::CommandExt;
let mut command = self.build_command();
let error = command.exec();
- Err(process_error(&format!("could not execute process `{}`",
- self.debug_string()),
- Some(Box::new(error)), None, None))
+ Err(CargoError::with_chain(error,
+ CargoErrorKind::ProcessErrorKind(
+ process_error(&format!("could not execute process `{}`",
+ self.debug_string()), None, None))))
}
#[cfg(windows)]
- pub fn exec_replace(&self) -> Result<(), ProcessError> {
+ pub fn exec_replace(&self) -> CargoResult<()> {
self.exec()
}
- pub fn exec_with_output(&self) -> Result<Output, ProcessError> {
+ pub fn exec_with_output(&self) -> CargoResult<Output> {
let mut command = self.build_command();
- let output = command.output().map_err(|e| {
- process_error(&format!("could not execute process `{}`",
- self.debug_string()),
- Some(Box::new(e)), None, None)
+ let output = command.output().chain_err(|| {
+ CargoErrorKind::ProcessErrorKind(
+ process_error(
+ &format!("could not execute process `{}`", self.debug_string()),
+ None, None))
})?;
if output.status.success() {
Ok(output)
} else {
- Err(process_error(&format!("process didn't exit successfully: `{}`",
+ Err(CargoErrorKind::ProcessErrorKind(process_error(&format!("process didn't exit successfully: `{}`",
self.debug_string()),
- None, Some(&output.status), Some(&output)))
+ Some(&output.status), Some(&output))).into())
}
}
pub fn exec_with_streaming(&self,
on_stdout_line: &mut FnMut(&str) -> CargoResult<()>,
on_stderr_line: &mut FnMut(&str) -> CargoResult<()>)
- -> Result<Output, ProcessError> {
+ -> CargoResult<Output> {
let mut stdout = Vec::new();
let mut stderr = Vec::new();
}
})?;
child.wait()
- })().map_err(|e| {
- process_error(&format!("could not execute process `{}`",
- self.debug_string()),
- Some(Box::new(e)), None, None)
+ })().chain_err(|| {
+ CargoErrorKind::ProcessErrorKind(
+ process_error(&format!("could not execute process `{}`",
+ self.debug_string()),
+ None, None))
})?;
let output = Output {
stdout: stdout,
status: status,
};
if !output.status.success() {
- Err(process_error(&format!("process didn't exit successfully: `{}`",
+ Err(CargoErrorKind::ProcessErrorKind(process_error(&format!("process didn't exit successfully: `{}`",
self.debug_string()),
- None, Some(&output.status), Some(&output)))
+ Some(&output.status), Some(&output))).into())
} else if let Some(e) = callback_error {
- Err(process_error(&format!("failed to parse process output: `{}`",
- self.debug_string()),
- Some(Box::new(e)), Some(&output.status), Some(&output)))
+ Err(CargoError::with_chain(e,
+ CargoErrorKind::ProcessErrorKind(
+ process_error(&format!("failed to parse process output: `{}`",
+ self.debug_string()), Some(&output.status), Some(&output)))))
} else {
Ok(output)
}
use std::path::PathBuf;
-use util::{self, CargoResult, internal, ChainError, ProcessBuilder};
+use util::{self, CargoResult, internal, ProcessBuilder};
pub struct Rustc {
pub path: PathBuf,
let host = {
let triple = verbose_version.lines().find(|l| {
l.starts_with("host: ")
- }).map(|l| &l[6..]);
- let triple = triple.chain_error(|| {
- internal("rustc -v didn't have a line for `host:`")
- })?;
+ }).map(|l| &l[6..]).ok_or(internal("rustc -v didn't have a line for `host:`"))?;
triple.to_string()
};
use core::manifest::{LibKind, Profile, ManifestMetadata};
use ops::is_bad_artifact_name;
use sources::CRATES_IO;
-use util::{self, CargoResult, human, ToUrl, ToSemver, ChainError, Config};
+use util::{self, CargoResult, human, ToUrl, ToSemver, Config};
+use util::errors::CargoResultExt;
/// Representation of the projects file layout.
///
return Ok(ret)
}
- Err(first_error).chain_error(|| {
+ Err(first_error).chain_err(|| {
human("could not parse input as TOML")
})
}
let mut warnings = vec![];
let project = me.project.as_ref().or_else(|| me.package.as_ref());
- let project = project.chain_error(|| {
+ let project = project.ok_or_else(|| {
human("no `package` or `project` section found.")
})?;
-> CargoResult<Vec<(PackageIdSpec, Dependency)>> {
let mut replace = Vec::new();
for (spec, replacement) in self.replace.iter().flat_map(|x| x) {
- let mut spec = PackageIdSpec::parse(spec).chain_error(|| {
+ let mut spec = PackageIdSpec::parse(spec).chain_err(|| {
human(format!("replacements must specify a valid semver \
version to replace, but `{}` does not",
spec))
let dep = replacement.to_dependency(spec.name(), cx, None)?;
let dep = {
- let version = spec.version().chain_error(|| {
+ let version = spec.version().ok_or_else(||
+ {
human(format!("replacements must specify a version \
to replace, but `{}` does not",
spec))
[dependencies]
curl = "0.4"
+error-chain = "0.10.0"
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
extern crate curl;
extern crate url;
+#[macro_use]
+extern crate error_chain;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;
use std::collections::HashMap;
-use std::fmt;
use std::fs::File;
use std::io::prelude::*;
use std::io::{self, Cursor};
-use std::result;
use curl::easy::{Easy, List};
use url::percent_encoding::{percent_encode, QUERY_ENCODE_SET};
+error_chain! {
+ foreign_links {
+ Curl(curl::Error);
+ Io(io::Error);
+ Json(serde_json::Error);
+ }
+
+ errors {
+ NotOkResponse(code: u32, headers: Vec<String>, body: Vec<u8>){
+ description("failed to get a 200 OK response")
+ display("failed to get a 200 OK response, got {}
+headers:
+ {}
+body:
+{}", code, headers.join("\n ", ), String::from_utf8_lossy(body))
+ }
+ NonUtf8Body {
+ description("response body was not utf-8")
+ display("response body was not utf-8")
+ }
+ Api(errs: Vec<String>) {
+ display("api errors: {}", errs.join(", "))
+ }
+ Unauthorized {
+ display("unauthorized API access")
+ }
+ TokenMissing{
+ display("no upload token found, please run `cargo login`")
+ }
+ NotFound {
+ display("cannot find crate")
+ }
+ }
+ }
+
pub struct Registry {
host: String,
token: Option<String>,
handle: Easy,
}
-pub type Result<T> = result::Result<T, Error>;
-
#[derive(PartialEq, Clone, Copy)]
pub enum Auth {
Authorized,
- Unauthorized
-}
-
-pub enum Error {
- Curl(curl::Error),
- NotOkResponse(u32, Vec<String>, Vec<u8>),
- NonUtf8Body,
- Api(Vec<String>),
Unauthorized,
- TokenMissing,
- Io(io::Error),
- NotFound,
- Json(serde_json::Error),
-}
-
-impl From<serde_json::Error> for Error {
- fn from(err: serde_json::Error) -> Error {
- Error::Json(err)
- }
-}
-
-impl From<curl::Error> for Error {
- fn from(err: curl::Error) -> Error {
- Error::Curl(err)
- }
}
#[derive(Deserialize)]
pub struct Crate {
pub name: String,
pub description: Option<String>,
- pub max_version: String
+ pub max_version: String,
}
#[derive(Serialize)]
// <json request> (metadata for the package)
// <le u32 of tarball>
// <source tarball>
- let stat = tarball.metadata().map_err(Error::Io)?;
+ let stat = tarball.metadata()?;
let header = {
let mut w = Vec::new();
w.extend([
let token = match self.token.as_ref() {
Some(s) => s,
- None => return Err(Error::TokenMissing),
+ None => return Err(Error::from_kind(ErrorKind::TokenMissing)),
};
self.handle.put(true)?;
self.handle.url(&url)?;
headers.append(&format!("Authorization: {}", token))?;
self.handle.http_headers(headers)?;
- let body = handle(&mut self.handle, &mut |buf| {
- body.read(buf).unwrap_or(0)
- })?;
+ let body = handle(&mut self.handle, &mut |buf| body.read(buf).unwrap_or(0))?;
let response = if body.len() > 0 {
body.parse::<serde_json::Value>()?
"{}".parse()?
};
- let invalid_categories: Vec<String> =
- response.get("warnings")
- .and_then(|j| j.get("invalid_categories"))
- .and_then(|j| j.as_array())
- .map(|x| {
- x.iter().flat_map(|j| j.as_str()).map(Into::into).collect()
- })
- .unwrap_or_else(Vec::new);
-
- let invalid_badges: Vec<String> =
- response.get("warnings")
- .and_then(|j| j.get("invalid_badges"))
- .and_then(|j| j.as_array())
- .map(|x| {
- x.iter().flat_map(|j| j.as_str()).map(Into::into).collect()
- })
- .unwrap_or_else(Vec::new);
+ let invalid_categories: Vec<String> = response
+ .get("warnings")
+ .and_then(|j| j.get("invalid_categories"))
+ .and_then(|j| j.as_array())
+ .map(|x| x.iter().flat_map(|j| j.as_str()).map(Into::into).collect())
+ .unwrap_or_else(Vec::new);
+
+ let invalid_badges: Vec<String> = response
+ .get("warnings")
+ .and_then(|j| j.get("invalid_badges"))
+ .and_then(|j| j.as_array())
+ .map(|x| x.iter().flat_map(|j| j.as_str()).map(Into::into).collect())
+ .unwrap_or_else(Vec::new);
Ok(Warnings {
invalid_categories: invalid_categories,
if authorized == Auth::Authorized {
let token = match self.token.as_ref() {
Some(s) => s,
- None => return Err(Error::TokenMissing),
+ None => return Err(Error::from_kind(ErrorKind::TokenMissing)),
};
headers.append(&format!("Authorization: {}", token))?;
}
match handle.response_code()? {
0 => {} // file upload url sometimes
200 => {}
- 403 => return Err(Error::Unauthorized),
- 404 => return Err(Error::NotFound),
- code => return Err(Error::NotOkResponse(code, headers, body))
+ 403 => return Err(Error::from_kind(ErrorKind::Unauthorized)),
+ 404 => return Err(Error::from_kind(ErrorKind::NotFound)),
+ code => return Err(Error::from_kind(ErrorKind::NotOkResponse(code, headers, body))),
}
let body = match String::from_utf8(body) {
Ok(body) => body,
- Err(..) => return Err(Error::NonUtf8Body),
+ Err(..) => return Err(Error::from_kind(ErrorKind::NonUtf8Body)),
};
match serde_json::from_str::<ApiErrorList>(&body) {
Ok(errors) => {
- return Err(Error::Api(errors.errors.into_iter().map(|s| s.detail)
- .collect()))
+ return Err(Error::from_kind(ErrorKind::Api(errors
+ .errors
+ .into_iter()
+ .map(|s| s.detail)
+ .collect())))
}
Err(..) => {}
}
Ok(body)
}
-
-impl fmt::Display for Error {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- Error::NonUtf8Body => write!(f, "response body was not utf-8"),
- Error::Curl(ref err) => write!(f, "http error: {}", err),
- Error::NotOkResponse(code, ref headers, ref body) => {
- writeln!(f, "failed to get a 200 OK response, got {}", code)?;
- writeln!(f, "headers:")?;
- for header in headers {
- writeln!(f, " {}", header)?;
- }
- writeln!(f, "body:")?;
- writeln!(f, "{}", String::from_utf8_lossy(body))?;
- Ok(())
- }
- Error::Api(ref errs) => {
- write!(f, "api errors: {}", errs.join(", "))
- }
- Error::Unauthorized => write!(f, "unauthorized API access"),
- Error::TokenMissing => write!(f, "no upload token found, please run `cargo login`"),
- Error::Io(ref e) => write!(f, "io error: {}", e),
- Error::NotFound => write!(f, "cannot find crate"),
- Error::Json(ref e) => write!(f, "json error: {}", e),
- }
- }
-}
use url::Url;
use hamcrest as ham;
use cargo::util::ProcessBuilder;
-use cargo::util::ProcessError;
+use cargo::util::{CargoError, CargoErrorKind, ProcessError};
use support::paths::CargoPathExt;
match res {
Ok(out) => self.match_output(&out),
- Err(ProcessError { output: Some(ref out), .. }) => {
+ Err(CargoError(CargoErrorKind::ProcessErrorKind(ProcessError { output: Some(ref out), .. }), ..)) => {
self.match_output(out)
}
Err(e) => {
extern crate cargotest;
extern crate hamcrest;
+extern crate cargo;
use std::str;
use std::fs;
use cargotest::support::{project, execs, path2url};
use cargotest::support::registry::Package;
use hamcrest::{assert_that, existing_file, existing_dir, is_not};
+use cargo::util::{CargoError, CargoErrorKind};
#[test]
fn simple() {
pub fn foo() {}
");
- let output = p.cargo_process("doc").exec_with_output().err().unwrap()
- .output.unwrap();
- let stderr = str::from_utf8(&output.stderr).unwrap();
- assert!(stderr.contains("☃"), "no snowman\n{}", stderr);
- assert!(stderr.contains("unknown start of token"), "no message\n{}", stderr);
+ let error = p.cargo_process("doc").exec_with_output().err().unwrap();
+ if let CargoError(CargoErrorKind::ProcessErrorKind(perr), ..) = error {
+ let output = perr.output.unwrap();
+ let stderr = str::from_utf8(&output.stderr).unwrap();
+
+ assert!(stderr.contains("☃"), "no snowman\n{}", stderr);
+ assert!(stderr.contains("unknown start of token"), "no message\n{}", stderr);
+ }else{
+ assert!(false, "an error kind other than ProcessErrorKind was encountered\n");
+ }
}
#[test]
-#[macro_use]
extern crate cargotest;
extern crate flate2;
extern crate git2;